﻿// -----------------------------------------------------------------------
// <copyright file="NotifyList.cs" company="Microsoft">
// TODO: Update copyright text.
// </copyright>
// -----------------------------------------------------------------------

namespace Proto
{
    using System;
    using System.Collections.Generic;
    using System.Collections;

    public class NotifyList<T_VALUE> : IEnumerable<T_VALUE>
    {
        public NotifyList()
        {
            m_Items = new List<T_VALUE>();
        }

        private readonly List<T_VALUE> m_Items;

        public IEnumerable<T_VALUE> Items
        {
            get
            {
                return m_Items;
            }
        }

        public int Count
        {
            get
            {
                return m_Items.Count;
            }
        }

        public void Add(T_VALUE item)
        {
            m_Items.Add(item);
            this.NotifyAdditionPending(item, m_Items.Count);
        }

        public void Add(T_VALUE addition, int index)
        {
            if (index < m_Items.Count)
            {
                this.NotifyAdditionPending(addition, index);
                m_Items.Insert(index, addition);
            }
            else
            {
                this.NotifyAdditionPending(addition, m_Items.Count - 1);
                m_Items.Add(addition);
            }
        }

        public void Remove(T_VALUE item)
        {
            // TODO: performance suck.
            int index = m_Items.IndexOf(item);
            if (index == -1)
            {
                throw new Exception("Potential multithreading exception");
                //return; 
            }
            Remove(item, index);
        }

        public void Remove(T_VALUE item, int index)
        {
            this.NotifyRemovalPending(item, index);
            m_Items.RemoveAt(index);
        }

        public void Remove(int index)
        {
            Remove(m_Items[index], index);
        }

        public T_VALUE this[int index]
        {
            get
            {
                return m_Items[index];
            }
            set
            {
                T_VALUE old = m_Items[index];
                T_VALUE new_value = value;
                NotifyUpdatePending( new_value, old, index );
                m_Items[index] = value;
            }
        }

        public event UpdateNotice<T_VALUE> NotifyUpdatePending = delegate { };
        public event AdditionNotice<T_VALUE> NotifyAdditionPending = delegate { };

        public event RemovalNotice<T_VALUE> NotifyRemovalPending = delegate { };

        public event Action NotifyClearPending = delegate { };

        public void Clear()
        {
            NotifyClearPending();
            m_Items.Clear();
        }

        #region Implementation of IEnumerable

        public IEnumerator<T_VALUE> GetEnumerator()
        {
            return m_Items.GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }

        #endregion

    }
}